#include "VParsing.h"
#include "VFunctions.h"
#include "VFileData.h"
#include "QFileInfo"

#include <QStringList>
#include <QDebug>
#include <QRegularExpression>
#include <QRegularExpressionMatch>

VParsing::VParsing(QString text)
{
    _text = text;
}

VParsing::~VParsing()
{

}

void VParsing::parsing_words(VWords *words)
{
    words->clear();
    VWords * temp;
    VWords * function_ptr;
    VWords * of_ptr;
    QRegExp reg;
    QString document = VFunctions::ctags(_text);
    QStringList list = document.split("\r\n");
//    qDebug() << "parsing";
    foreach(QString line_text, list)
    {
        int line;
        QString name;
        QString s_kind;
        QString type_name;
        QString function;
        QString signature;

        if(line_text.length() == 0)
        {
            continue;
        }

        if(line_text.at(0) == '!')
        {
            continue;
        }

        reg.setPattern("([\u4e00-\u9fa5_.a-zA-Z0-9]+)\\t");
        if(reg.indexIn(line_text) != -1)
            name = reg.cap(1);

        reg.setPattern("line:(\\d+)");
        if(reg.indexIn(line_text) != -1)
            line = reg.cap(1).toInt();

        reg.setPattern("kind:(\\w+)");
        if(reg.indexIn(line_text) != -1)
            s_kind = reg.cap(1);

        reg.setPattern("typeref:\\w+:([\u4e00-\u9fa5_*a-zA-Z0-9 ]+)");
        if(reg.indexIn(line_text) != -1)
            type_name = reg.cap(1);
//        qDebug() << type_name;

        reg.setPattern("function:([\u4e00-\u9fa5_.a-zA-Z0-9]+)");
        if(reg.indexIn(line_text) != -1)
            function = reg.cap(1);

        reg.setPattern("signature:\\((.+)\\)");
        if(reg.indexIn(line_text) != -1)
            signature = reg.cap(1);

//        qDebug() << signature;

        int kind;
        if(s_kind == "function")
        {
            kind = VWords::KIND::FUNCTION;
        }
        else if(s_kind == "parameter")
        {
            kind = VWords::KIND::PARAMETER;
        }
        else if(s_kind == "macro")
        {
            kind = VWords::KIND::MARCO;
        }
        else if(s_kind == "variable")
        {
            kind = VWords::KIND::VARIABLE;
        }
        else if(s_kind == "local")
        {
            kind = VWords::KIND::LOCAL;
        }
        else if(s_kind == "prototype")
        {
            kind = VWords::KIND::PROTOTYPE;
        }
        else if(s_kind == "enumerator")
        {
            kind = VWords::KIND::ENUMERATOR;
        }
        else if(s_kind == "enum")
        {
            kind = VWords::KIND::ENUM;
        }
        else if(s_kind == "typedef")
        {
            kind = VWords::KIND::TYPEDEF;
        }
        else if(s_kind == "struct")
        {
            kind = VWords::KIND::STRUCT;
        }
        else if(s_kind == "union")
        {
            kind = VWords::KIND::UNION;
        }
        else if(s_kind == "member")
        {
            kind = VWords::KIND::MEMBER;
        }
        else if(s_kind == "label")
        {
            kind = VWords::KIND::LABEL;
        }

        if(function.isEmpty())
        {
            temp = words;
        }
        else
        {
            function_ptr = words->matching_child(function, VWords::KIND::FUNCTION,
                                                  VWords::MATCH::NAME, -1, VWords::MODE::ALL);
            if(function_ptr == nullptr)
            {
                function_ptr = new VWords(function, "", "", -1, VWords::KIND::FUNCTION);
                words->append(function_ptr);
            }

            temp = function_ptr;
        }

        if(kind == VWords::KIND::MEMBER)
        {
            int of_kind = -1;
            QString of_name;
            reg.setPattern("(struct|union):(\\w+)");
            if(reg.indexIn(line_text) != -1)
            {
                if(reg.cap(1) == "struct")
                {
                    of_kind = VWords::KIND::STRUCT;
                }
                else if(reg.cap(1) == "union")
                {
                    of_kind = VWords::KIND::UNION;
                }


                of_name = reg.cap(2);
            }

            if(of_kind == -1 ||
                    of_name.isEmpty())
            {
                continue;
            }

            of_ptr = temp->matching_child(of_name, of_kind, VWords::MATCH::NAME,
                                                        -1, VWords::MODE::ALL);

            if(of_ptr == nullptr)
            {
                if(reg.cap(1) == "struct")
                {
                    of_ptr = new VWords(of_name, "", "", -1, of_kind);
                }
                else
                {
                    of_ptr = new VWords(of_name, "", "", -1, of_kind);
                }
                temp->append(of_ptr);
            }
        }

        switch (kind) {
        case VWords::KIND::MEMBER:
            of_ptr->append(new VWords(name, type_name, signature, line, kind));
            break;

        case VWords::KIND::FUNCTION:
            function_ptr = temp->matching_child(name, VWords::KIND::FUNCTION,
                                                  VWords::MATCH::NAME, -1, VWords::MODE::ALL);
            if(function_ptr == nullptr)
            {
                function_ptr = new VWords(name, type_name, signature, line, VWords::KIND::FUNCTION);
                temp->append(function_ptr);
            }
            else
            {
                function_ptr->_type_name = type_name;
                function_ptr->_signature = signature;
                function_ptr->_line = line;
            }
            break;

        case VWords::KIND::STRUCT:
        case VWords::KIND::UNION:
            of_ptr = words->matching_child(name, kind, VWords::MATCH::NAME,
                                            -1, VWords::MODE::ALL);
            if(of_ptr == nullptr)
            {
                of_ptr = new VWords(name, type_name, signature, line, kind);
                temp->append(of_ptr);
            }
            else
            {
                of_ptr->_type_name = type_name;
                of_ptr->_signature = signature;
                of_ptr->_line = line;
            }

            break;
        default:
            temp->append(new VWords(name, type_name, signature, line, kind));
            break;
        }
    }
//    qDebug() << "parsing end";

//        qDebug() << "kind" << kind;
//        if(kind == "function")
//        {
//            auto ptr = find_vword(_word_list ,name, VWords::KIND::FUNCTION);
//            if(ptr == nullptr)
//            {
//                _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::FUNCTION));
//            }
//            else
//            {
//                ptr->_line = line;
//                ptr->_type_name = type_name;
//                ptr->_signature = signature;
//            }

//        }
//        else if(kind == "parameter")
//        {
//            auto ptr = find_vword(_word_list ,function, VWords::KIND::FUNCTION);
//            if(ptr == nullptr)
//            {
//                auto new_ptr = new VWords(function, "", "", 0, VWords::KIND::FUNCTION);
//                new_ptr->add_parameter(new VWords(name, type_name, "", line, VWords::KIND::PARAMETER));
//                _word_list.append(new_ptr);
//            }
//            else
//            {
//                ptr->add_parameter(new VWords(name, type_name, "", line, VWords::KIND::PARAMETER));
//            }
//        }
//        else if(kind == "macro")
//        {
//            _word_list.append(new VWords(name, type_name, "", line, VWords::KIND::MARCO));
//        }
//        else if(kind == "variable")
//        {
//            _word_list.append(new VWords(name, type_name, "", line, VWords::KIND::VARIABLE));
//        }
//        else if(kind == "local")
//        {
//            auto ptr = find_vword(_word_list ,function, VWords::KIND::FUNCTION);
//            if(ptr == nullptr)
//            {
//                auto new_ptr = new VWords(function, "", "", 0, VWords::KIND::FUNCTION);
//                new_ptr->add_parameter(new VWords(name, type_name, "", line, VWords::KIND::LOCAL));
//                _word_list.append(new_ptr);
//            }
//            else
//            {
//                ptr->add_lcoal(new VWords(name, type_name, "", line, VWords::KIND::LOCAL));
//            }
//        }
//        else if(kind == "prototype")
//        {
//            _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::PROTOTYPE));
//        }
//        else if(kind == "enumerator")
//        {
//            _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::ENUMERATOR));
//        }
//        else if(kind == "enum")
//        {
//            _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::ENUM));
//        }
//        else if(kind == "typedef")
//        {
//            _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::TYPEDEF));
//        }
//        else if(kind == "struct")
//        {
//            auto ptr = find_vword(_word_list ,name, VWords::KIND::STRUCT);
//            if(ptr == nullptr)
//            {
//                 _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::STRUCT));
//            }
//            else
//            {
//                ptr->_line = line;
//                ptr->_type_name = type_name;
//                ptr->_signature = signature;
//            }

//        }
//        else if(kind == "union")
//        {
//            auto ptr = find_vword(_word_list ,name, VWords::KIND::UNION);
//            if(ptr == nullptr)
//            {
//                 _word_list.append(new VWords(name, type_name, signature, line, VWords::KIND::UNION));
//            }
//            else
//            {
//                ptr->_line = line;
//                ptr->_type_name = type_name;
//                ptr->_signature = signature;
//            }

//        }
//        else if(kind == "member")
//        {
//            int find_type;
//            QString of_name;
//            if(line_text.indexOf("struct:") != -1)
//            {
//                find_type = VWords::KIND::STRUCT;
//                reg.setPattern("struct:(\\w+)");
//                if(reg.indexIn(line_text) != -1)
//                    of_name = reg.cap(1);
//            }
//            else
//            {
//                find_type = VWords::KIND::UNION;
//                reg.setPattern("union:(\\w+)");
//                if(reg.indexIn(line_text) != -1)
//                    of_name = reg.cap(1);
//            }

//            auto ptr = find_vword(_word_list , of_name, find_type);
//            if(ptr == nullptr)
//            {
//                auto new_ptr = new VWords(of_name, type_name, signature, line, find_type);
//                new_ptr->add_member(new VWords(name, type_name, "", line, VWords::KIND::MEMBER));
//                _word_list.append(new_ptr);
//            }
//            else
//            {
//                ptr->add_member(new VWords(name, type_name, "", line, VWords::KIND::MEMBER));
//            }
//        }
//    }

//    foreach(VWords *ptr, _word_list)
//    {
//        qDebug() << ptr->_name;
//    }
}

void VParsing::parsing_include(QList<VFileData::VHeadFile> &list)
{
    list.clear();

    QRegularExpression reg;
    QRegularExpressionMatch match;

    reg.setPattern("#(include|引入)\\s+(\"|<)(.+)(\"|>)");
    match = reg.match(_text);
    while(match.hasMatch())
    {
        QFileInfo info(match.captured(3).trimmed());
        QString name = info.fileName();
        QString path = info.path();

        qDebug() << name << " " << path;
        if(match.captured(2) == "<")
        {
            list.append(VFileData::VHeadFile(name, path ,VFileData::VHeadFileType::STD));
        }
        else
        {
            list.append(VFileData::VHeadFile(name, path ,VFileData::VHeadFileType::STDEX));
        }
        match = reg.match(_text, match.capturedEnd());
    }
}
